﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.ComponentModel.DataAnnotations;

namespace VideoClipNameHelper
{
    public class UsageStatistic
    {
        //public int RecordId { get; set; }
        [Required, Key, MaxLength(256)]
        public string clipName { get; set; }//nvarchar(256) PRIMARY KEY,
        public int nPlayed { get; set; }
        public int nSkipped { get; set; }
        public bool isDeleted { get; set; }
        public bool isLiked { get; set; }
        //
        public override string ToString()
        {
            return string.Format($"{clipName}\t{nPlayed}\t{nSkipped}\t{isDeleted}\t{isLiked}");
        }
    }

    public class UsageStatisticContext: System.Data.Entity.DbContext
    {
        //public UsageStatisticContext(): base("ConnectionString")
        public UsageStatisticContext() : base(SelectConnectionString())
        {

            System.Data.Entity.Database.SetInitializer<UsageStatisticContext>(new System.Data.Entity.CreateDatabaseIfNotExists<UsageStatisticContext>());
            //System.Data.Entity.Database.SetInitializer<UsageStatisticContext>(new System.Data.Entity.DropCreateDatabaseIfModelChanges<UsageStatisticContext>());
            //System.Data.Entity.Database.SetInitializer<UsageStatisticContext>(new System.Data.Entity.DropCreateDatabaseAlways<UsageStatisticContext>());
            //System.Data.Entity.Database.SetInitializer<UsageStatisticContext>(new UsageStatisticDBInitializer());
        }
        public System.Data.Entity.DbSet<UsageStatistic> UsageStatistics { get; set; }

        private static string SelectConnectionString()
        {
            if("MMM64" == Environment.MachineName)
            {
                return "ConnectionStringDebug";
            }
            return "ConnectionString";
        }
        /*
        private static string ConnectionString()
        {
            System.Data.SqlClient.SqlConnectionStringBuilder sqlBuilder = new System.Data.SqlClient.SqlConnectionStringBuilder();
            sqlBuilder.DataSource = "XXX";
            sqlBuilder.InitialCatalog = "YYY";
            sqlBuilder.PersistSecurityInfo = true;
            sqlBuilder.IntegratedSecurity = true;
            sqlBuilder.MultipleActiveResultSets = true;

            return sqlBuilder.ToString();
        }
        */

    }
    public class CDBHandler
    {
        public static bool IsFailed = false;
        //
        public static void Initialize()
        {
            System.Data.Entity.Database.SetInitializer<UsageStatisticContext>(new System.Data.Entity.CreateDatabaseIfNotExists<UsageStatisticContext>());
        }

        public static string DbInfo()
        {
            string s = "";
            string NL = Environment.NewLine;
            try
            {
                using (var context = new UsageStatisticContext())
                {
                    s += $"ConnectionString:{context.Database.Connection.ConnectionString}{NL}";
                    s += $"Database:{context.Database.Connection.Database}{NL}";
                    s += $"DataSource:{context.Database.Connection.DataSource}{NL}";
                    s += $"ServerVersion:{context.Database.Connection.ServerVersion}{NL}";
                    s += $"State{context.Database.Connection.State}";
                    //
                }
            }
            catch(Exception e)
            {
                s = "ERROR: " + e.Message;
            }
            return s;
        }

        //
        /// <summary>
        /// 
        /// </summary>
        /// <param name="clipName">Forma Concat Short</param>
        /// <param name="updatenPlayed">true: inkrementacja, false: nic</param>
        /// <param name="updatenSkipped">true: inkrementacja, false: nic</param>
        /// <param name="isDeleted">null: nic, true/false: zapisane do rekordu</param>
        /// <param name="isLiked">null: nic, true/false: zapisane do rekordu</param>
        /// <returns></returns>
        public static async Task<bool> UpdateData(string clipName, bool updatenPlayed = false, bool updatenSkipped = false, bool? isDeleted = null, bool? isLiked = null)
        {
            if (IsFailed)
            {
                return false;
            }
            //
            try
            {
                using (var context = new UsageStatisticContext())
                {
                    //context.Configuration.LazyLoadingEnabled = false;
                    //
                    UsageStatistic found = context.UsageStatistics.FirstOrDefault<UsageStatistic>(x => 0 == string.Compare(x.clipName, clipName, true));
                    if (null == found)
                    {
                        UsageStatistic uc = new UsageStatistic();
                        uc.clipName = clipName;
                        uc.nPlayed = updatenPlayed ? 1 : 0;
                        uc.nSkipped = updatenSkipped ? 1 : 0;
                        if (null != isDeleted) uc.isDeleted = (bool)isDeleted;
                        if (null != isLiked) uc.isLiked = (bool)isLiked;
                        context.UsageStatistics.Add(uc);
                    }
                    else
                    {
                        found.nPlayed = updatenPlayed ? found.nPlayed + 1 : found.nPlayed;
                        found.nSkipped = updatenSkipped ? found.nSkipped + 1 : found.nSkipped;
                        if (null != isDeleted) found.isDeleted = (bool)isDeleted;
                        if (null != isLiked) found.isLiked = (bool)isLiked;
                    }
                    await context.SaveChangesAsync();
                }
            }
            catch
            {
                IsFailed = true;
                //Console.WriteLine("DB Failed");
            }
            //
            return true;
        }

        public static async Task<bool> UpdateClipName(string clipNameOld, string clipNameNew)
        {
            if (IsFailed)
            {
                return false;
            }
            //
            try
            {
                using (var context = new UsageStatisticContext())
                {
                    //context.Configuration.LazyLoadingEnabled = false;
                    //
                    UsageStatistic found = context.UsageStatistics.FirstOrDefault<UsageStatistic>(x => 0 == string.Compare(x.clipName, clipNameOld, true));
                    if (null == found)
                    {
                        return false;
                    }
                    else
                    {
                        await WriteRecord(clipNameNew, found.nPlayed, found.nSkipped, found.isDeleted, found.isLiked);
                        await DeleteRecord(found.clipName);
                    }
                    //await context.SaveChangesAsync();
                }
            }
            catch
            {
                IsFailed = true;
                return false;
            }
            //
            return true;
        }

        public static async Task<bool> WriteRecord(string clipName, int nPlayed, int nSkipped, bool? isDeleted, bool? isLiked)
        {
            if (IsFailed)
            {
                return false;
            }
            //
            try
            {
                using (var context = new UsageStatisticContext())
                {
                    UsageStatistic found = context.UsageStatistics.FirstOrDefault<UsageStatistic>(x => 0 == string.Compare(x.clipName, clipName, true));
                    if (null == found)
                    {
                        UsageStatistic uc = new UsageStatistic();
                        uc.clipName = clipName;
                        uc.nPlayed = nPlayed;
                        uc.nSkipped = nSkipped;
                        if (null != isDeleted) uc.isDeleted = (bool)isDeleted;
                        if (null != isLiked) uc.isLiked = (bool)isLiked;
                        context.UsageStatistics.Add(uc);
                    }
                    else
                    {
                        found.nPlayed = nPlayed;
                        found.nSkipped = nSkipped;
                        if (null != isDeleted) found.isDeleted = (bool)isDeleted;
                        if (null != isLiked) found.isLiked = (bool)isLiked;
                    }
                    await context.SaveChangesAsync();
                }
            }
            catch//(Exception e)
            {
                //Console.WriteLine(">>>>>>>>>>>"+e.Message);
                IsFailed = true;
                //Console.WriteLine("DB Failed");
            }
            //
            return true;
        }

        public static async Task<bool> DeleteRecord(string clipName)
        {
            if (IsFailed)
            {
                return false;
            }
            //
            try
            {
                using (var context = new UsageStatisticContext())
                {
                    UsageStatistic found = context.UsageStatistics.FirstOrDefault<UsageStatistic>(x => 0 == string.Compare(x.clipName, clipName, true));
                    if (null != found)
                    {
                        context.UsageStatistics.Remove(found);
                    }
                    await context.SaveChangesAsync();
                }
            }
            catch//(Exception e)
            {
                //Console.WriteLine(">>>>>>>>>>>"+e.Message);
                IsFailed = true;
                //Console.WriteLine("DB Failed");
            }
            //
            return true;
        }

        //ref: System.Data.Linq
        //System.Data.Objects
        //System.Data.Entity.dll

        public static bool ScanData(Action<UsageStatistic> callback)
        {
            if (IsFailed)
            {
                return false;
            }
            //
            try
            {
                using (var context = new UsageStatisticContext())
                {
                    context.Configuration.LazyLoadingEnabled = false;
                    //
                    IOrderedQueryable query = context.UsageStatistics.Where(x => !x.isDeleted).OrderBy(x => x.clipName);
                        foreach (UsageStatistic found in query)
                    {
                        UsageStatistic us = new UsageStatistic();
                        us.clipName = found.clipName;
                        us.isDeleted = found.isDeleted;
                        us.isLiked = found.isLiked;
                        us.nPlayed = found.nPlayed;
                        us.nSkipped = found.nSkipped;
                        callback(us);
                    }
                }
            }
            catch(Exception ex)
            {

                IsFailed = true;
                return false;
            }
            //
            return true;
        }

        public static bool IsLiked(string clipName)
        {
            if (IsFailed)
            {
                return false;
            }
            //
            try
            {
                using (var context = new UsageStatisticContext())
                {
                    UsageStatistic found = context.UsageStatistics.FirstOrDefault<UsageStatistic>(x => (0 == string.Compare(x.clipName, clipName, true)) && !x.isDeleted);
                    if (null == found)
                    {
                        return false;
                    }
                    else
                    {
                        return found.isLiked;
                    }
                }
            }
            catch
            {
                IsFailed = true;
                //Console.WriteLine("DB Failed");
            }
            //
            return true;
        }

        public static async Task<bool> UpdateLike(string clipName, bool isLiked)
        {
            if (IsFailed)
            {
                return false;
            }
            //
            try
            {
                using (var context = new UsageStatisticContext())
                {
                    UsageStatistic found = context.UsageStatistics.FirstOrDefault<UsageStatistic>(x => 0 == string.Compare(x.clipName, clipName, true));
                    if (null == found)
                    {
                        UsageStatistic uc = new UsageStatistic();
                        uc.clipName = clipName;
                        uc.isLiked = isLiked;
                        context.UsageStatistics.Add(uc);
                    }
                    else
                    {
                        found.isLiked = isLiked;
                    }
                    await context.SaveChangesAsync();
                }
            }
            catch
            {
                IsFailed = true;
                //Console.WriteLine("DB Failed");
            }
            //
            return true;
        }

        public static List<string> GetLiked()
        {
            List<string> oList = new List<string>();

            if (IsFailed) return oList;
            //
            try
            {
                using (var context = new UsageStatisticContext())
                {
                    context.Configuration.LazyLoadingEnabled = false;
                    //
                    foreach (UsageStatistic found in context.UsageStatistics.Where(x => x.isLiked && !x.isDeleted))
                    {
                        oList.Add(found.clipName);
                    }
                }
            }
            catch
            {
                IsFailed = true;
            }
            //
            return oList;
        }


        public static int DumpDb(bool printPlayed = false, bool printSkipped = false, bool printDeleted = false, bool printLiked = false)
        {
            if (IsFailed) return -1;
            //
            int n = 0;
            try
            {
                using (var context = new UsageStatisticContext())
                {
                    context.Configuration.LazyLoadingEnabled = false;
                    //
                    Console.WriteLine("# Dump " + DateTime.Now.ToString());
                    IOrderedQueryable query = null;
                    if (!printPlayed && !printSkipped && !printDeleted && !printLiked)
                    {
                        query = context.UsageStatistics.OrderBy(x => x.clipName);
                    }
                    else if (printPlayed)
                    {
                        query = context.UsageStatistics.Where(x => x.nPlayed != 0 && !x.isDeleted).OrderBy(x => x.clipName);
                    }
                    else if (printSkipped)
                    {
                        query = context.UsageStatistics.Where(x => x.nSkipped != 0 && !x.isDeleted).OrderBy(x => x.clipName);
                    }
                    else if (printDeleted)
                    {
                        query = context.UsageStatistics.Where(x => x.isDeleted).OrderBy(x => x.clipName);
                    }
                    else if (printLiked)
                    {
                        query = context.UsageStatistics.Where(x=> x.isLiked && !x.isDeleted).OrderBy(x => x.clipName);
                    }

                    //foreach (UsageStatistic found in context.UsageStatistics.OrderBy(x => x.clipName))
                    foreach (UsageStatistic found in query)
                    {
                        Console.WriteLine(found.ToString());n++;
                    }
                    Console.WriteLine("# End Dump: "+ n.ToString());
                }
            }
            catch
            {
                IsFailed = true;
                return -1;
            }
            return n;
        }

        public static int DumpDb(string fName)
        {
            if (IsFailed) return -1;
            //
            int n = 0;
            try
            {
                List<string> ll = new List<string>();
                using (var context = new UsageStatisticContext())
                {
                    ll.Add("# Dump " + DateTime.Now.ToString());
                    foreach (UsageStatistic found in context.UsageStatistics.OrderBy(x => x.clipName))
                    {
                        ll.Add(found.ToString());n++;
                    }
                    ll.Add("# End Dump: " + n.ToString());
                }
                System.IO.File.WriteAllLines(fName, ll, Encoding.UTF8);
            }
            catch
            {
                IsFailed = true;
                return -1;
            }
            return n;
        }
    }//class
}//namespace
